文章同步於blog
今天要介紹依賴反向原則(DIP, Dependency Inversion Principle)
最靈活的系統是『原始碼的依賴關係指涉及抽象不涉及具體』
-Clean Architecture(P.75)
上述這段話的意思就是,我們應該將我的模組依賴於抽象概念
但這段話其實不切實際,特別像是Python這些大量依賴第三方套件的語言
基本上我們要做的功能已經有人幫我們做好了
甚至我們連依賴list.count()
這種都屬於依賴具體物件的方法
這種情況我們不可也不該避免
所以在應用DIP時,我們可以忽略作業系統的穩定背景,我們也可以信任他們不會改變。
要注意的是,系統中容易變化的具體元素。
同樣以php為例子
class Dog {
public function bark() {
return "汪!";
}
}
class Cat {
public function meow() {
return "喵~~";
}
}
class PetOwner {
private $dog;
private $cat;
public function __construct() {
$this->dog = new Dog();
$this->cat = new Cat();
}
public function playWithPets() {
$dogSound = $this->dog->bark();
$catSound = $this->cat->meow();
return "Dog: $dogSound, Cat: $catSound";
}
}
我們可以看到PetOwner
依賴於Dog
和Cat
假設未來我要多領養幾隻寵物,我就必須一直持續在petOwner
裡面一直新增
持續的對petOwner
做修改
萬一上層的class要做修改,那更改的範圍就會更大
換個方法
interface PetSound {
public function makeSound();
}
class Dog implements PetSound {
public function makeSound() {
return "汪!";
}
}
class Cat implements PetSound {
public function makeSound() {
return "喵~~";
}
}
class PetOwner {
private $pets = [];
public function addPet(PetSound $pet) {
$this->pets[] = $pet;
}
public function playWithPets() {
$sounds = [];
foreach ($this->pets as $pet) {
$sounds[] = $pet->makeSound();
}
return implode(", ", $sounds);
}
}
在這個例子中,我們引入了一個 PetSound
抽象介面,並讓 Dog
和 Cat
類實現這個介面PetOwner
類不再直接創建寵物的實例,而是通過 addPet
方法將寵物加入,並且在 playWithPets
方法中調用了抽象介面的方法。
這種做法降低了耦合度,使得我們可以較容易地擴展或修改代碼,而不會影響其他部分。這符合 DIP 原則的理念。
Clean Architecture(ch.11)